//===============================================================================
// Microsoft Architecture Strategy Team
// LitwareHR - SaaS Sample Application
//===============================================================================
// Copyright  Microsoft Corporation.  All rights reserved.
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.
//===============================================================================
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious.  No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
//===============================================================================

using System;
using System.Collections.Generic;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.IdentityModel.Tokens;
using System.ServiceModel.Security.Tokens;
using System.Threading;
using System.Xml;
using System.Web;

namespace Shp.Security.BrokeredSender
{    
    /// <summary> 
    /// Helper class used as cache for security tokens 
    /// </summary>
    static public class SecurityTokenCacheStore
    {
        private static Dictionary<Uri, SecurityToken> _tokens = new Dictionary<Uri, SecurityToken>();
        private static ReaderWriterLock _tokenLock = new ReaderWriterLock();

        private const int DefaultTimeout = 1000;
        private const string StsTokenKeyPrefix = "{27C96656-DF32-4773-A09C-6984E3C83177}";

        private static bool IsHttpContextAvailable = false;

        static SecurityTokenCacheStore()
        {
            IsHttpContextAvailable = (HttpContext.Current != null);
        }

        static public SecurityToken GetSecurityToken(Uri endpoint)
        {
            if (IsHttpContextAvailable)
                return GetSecurityTokenFromSession(endpoint);
            else
                return GetSecurityTokenFromDictionary(endpoint);

        }

        static public void AddSecurityToken(Uri endpoint, SecurityToken token)
        {
            if (IsHttpContextAvailable)
                AddSecurityTokenToSession(endpoint, token);
            else
                AddSecurityTokenToDictionary(endpoint, token);
        }

        private static void AddSecurityTokenToSession(Uri endpoint, SecurityToken token)
        {
            HttpContext.Current.Session[StsTokenKeyPrefix + endpoint.ToString()] = token;
        }

        private static void AddSecurityTokenToDictionary(Uri endpoint, SecurityToken token)
        {
            _tokenLock.AcquireWriterLock(DefaultTimeout);
            try
            {
                if (_tokens.ContainsKey(endpoint))
                    _tokens.Remove(endpoint);

                _tokens.Add(endpoint, token);
            }

            finally
            {
                _tokenLock.ReleaseWriterLock();
            }
        }

        private static SecurityToken GetSecurityTokenFromSession(Uri endpoint)
        {
            return HttpContext.Current.Session[StsTokenKeyPrefix + endpoint.ToString()] as SecurityToken;
        }

        private static SecurityToken GetSecurityTokenFromDictionary(Uri endpoint)
        {
            SecurityToken token = null;
            _tokenLock.AcquireReaderLock(DefaultTimeout);
            try
            {
                _tokens.TryGetValue(endpoint, out token);
                return token;
            }
            finally
            {
                _tokenLock.ReleaseReaderLock();
            }
        }

        static public void Clear()
        {
            if (IsHttpContextAvailable)
                ClearFromSession();
            else
                ClearFromDictionary();
        }

        private static void ClearFromDictionary()
        {
            _tokenLock.AcquireReaderLock(DefaultTimeout);
            try
            {
                _tokens.Clear();
            }
            finally
            {
                _tokenLock.ReleaseReaderLock();
            }
        }

        private static void ClearFromSession()
        {
            foreach (string key in HttpContext.Current.Session.Keys)
            {
                if (key.StartsWith(StsTokenKeyPrefix))
                    HttpContext.Current.Session.Remove(key);
            }
        }
    }
}